#ifndef Net_EPollServer_INCLUDED
#define Net_EPollServer_INCLUDED

#include <set>
#include <sys/epoll.h>
#include <deque>

#include "socket.h"
#include "mutex.h"
#include "event.h"
#include "runnable.h"
#include "thread.h"
#include "epolldispatcher.h"

using std::set;
using std::deque;

class EpollServer;

class FdTimeOutThread : public Runnable
{
public:
    FdTimeOutThread(EpollServer& server, int epollFd)
    :m_server(server),
    m_epollFd(epollFd),
    m_exitflag(false)
    {
    }
    
    virtual void run();

    void stop()
    {
        m_exitflag = true;
    }
private:
    friend class EpollServer;
    EpollServer&            m_server;
    int                     m_epollFd;
    bool                    m_exitflag;
    Event                   m_event;
};

class EpollServer: public Socket
{
public:
    EpollServer(const SocketAddress& address, EpollDispatcher& dispather,
            bool reuseAddress = true,EPOLL_MODE mode = EPOLLMODE_ET,
            int backlog = LISTEN_BACKLOG);

    EpollServer(unsigned int port, EpollDispatcher& dispather,bool reuseAddress = true,
            EPOLL_MODE mode = EPOLLMODE_ET,int backlog = LISTEN_BACKLOG);
    
    virtual ~EpollServer();
    
    void wait();

    void stopWait()
    {
        if (!m_exitflag)
        {
            m_timeoutTarget->stop();
            m_dispatcher.stop();
            m_timeoutThread.join();
            m_exitflag = true;
        }
    }
    
    int acceptConnection();
    
    void closingFd(int timeoutFd);
    
    /// monitor info
    bool running()
    {
        return !m_exitflag;
    }
    
    int closingFdSize()
    {
        ScopedMutex lock(&m_timeoutFdsMutex);
        return m_timeoutFds.size();
    }
    
    bool isEdegTrigerMode()
    {
        return m_mode == EPOLLMODE_ET;
    }

    void addMaxEvent(int n)
    {
        ScopedMutex lock(&m_timeoutFdsMutex);
        m_maxevent += n;
    }

    void reduceMaxEvent(int n)
    {
        ScopedMutex lock(&m_timeoutFdsMutex);
        m_maxevent -= n;
    }
private:
    EpollServer& operator = (const Socket& socket);
    void getTimeoutFds(std::set<int>& timeoutFds);
        /// get a copy of closing timeoutfds;
    friend class FdTimeOutThread;
    
    void init(unsigned long maxopenfd = MAXOPENFD);
    
private:
    int                 m_epollFd;
        /// initialize epoll
    bool                m_exitflag;
        /// exit control
    EpollDispatcher&    m_dispatcher;
        /// EpollDispatcher
    std::set<int>       m_timeoutFds;
        /// timeout fds
    Mutex               m_timeoutFdsMutex;
    Thread              m_timeoutThread;
    unsigned int        m_maxevent;
    unsigned int        m_event;
    FdTimeOutThread*    m_timeoutTarget;
    EPOLL_MODE          m_mode;
};

#endif



